package com.picolov;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class StringConverter {
	
	private static final int MAP_KEY_VALUE_SPLITTER = '=';
	private static final int MAP_ITEM_SPLITTER = ',';
	private static final int MAP_START_CHAR = '{';
	private static final int MAP_END_CHAR = '}';
	private static final int LIST_ITEM_SPLITTER = ',';
	private static final int LIST_START_CHAR = '[';
	private static final int LIST_END_CHAR = ']';
	
	private static String nullString = "null"; 
	private static boolean nullStringAsNullObject = true;
	private static boolean convertPossibleNumeric = true;
	
	public static void setNullStringAsNullObject(boolean treatAsNull) {
		nullStringAsNullObject = treatAsNull;
	}
	
	public static void setConvertPossibleNumeric(boolean convertNumeric) {
		convertPossibleNumeric = convertNumeric;
	}

	public static int convertStringToMap(String mapContent, Map<String, Object> resultMap) {
		mapContent = mapContent.trim();
		StringBuilder key = null;
		Object value = null;
		boolean isValue = false;
		for (int i = 1; i < mapContent.length(); i++) {
			if (mapContent.charAt(i) == MAP_KEY_VALUE_SPLITTER) {
				isValue = true;
			} else if (mapContent.charAt(i) == MAP_ITEM_SPLITTER) {
				if (value == null) {
					value = "";
				} else if (value instanceof String) {
					value = ((String) value).trim();
					if (nullStringAsNullObject && value.equals(nullString)) {
						value = null;
					} else if (convertPossibleNumeric) {
						try {
							value = Integer.parseInt((String) value);
						} catch (Exception e) {
						}
					}
				}
				resultMap.put(key.toString().trim(), value);
				isValue = false;
				key = new StringBuilder();
				value = null;
			} else if (mapContent.charAt(i) == MAP_END_CHAR) {
				if (key == null && value == null) {
					return i;
				} else if (value == null) {
					value = "";
				} else if (value instanceof String) {
					value = ((String) value).trim();
					if (nullStringAsNullObject && value.equals(nullString)) {
						value = null;
					} else if (convertPossibleNumeric) {
						try {
							value = Integer.parseInt((String) value);
						} catch (Exception e) {
						}
					}
				}
				resultMap.put(key.toString().trim(), value);
				return i;
			} else {
				if (isValue) {
					if (mapContent.charAt(i) == MAP_START_CHAR) {
						value = new HashMap<String, Object>();
						int skipPos = convertStringToMap(mapContent.substring(i), (HashMap<String, Object>) value);
						i += skipPos;
					} else if (mapContent.charAt(i) == LIST_START_CHAR) {
						value = new ArrayList<Object>();
						int skipPos = convertStringToList(mapContent.substring(i), (List<Object>) value);
						i += skipPos;
					} else {
						if (value == null)
							value = "";
						value = (String)value + mapContent.charAt(i);
					}
				} else {
					if (key == null)
						key = new StringBuilder();
					key.append(mapContent.charAt(i));
				}
			}
		}
		return 0;
	}

	public static int convertStringToList(String mapContent, List<Object> list) {
		mapContent = mapContent.trim();
		Object value = null;
		for (int i = 1; i < mapContent.length(); i++) {
			if (mapContent.charAt(i) == LIST_ITEM_SPLITTER) {
				if (value == null) {
					value = "";
				} else if (value instanceof String) {
					value = ((String) value).trim();
					if (nullStringAsNullObject && value.equals(nullString)) {
						value = null;
					} else if (convertPossibleNumeric) {
						try {
							value = Integer.parseInt((String) value);
						} catch (Exception e) {
						}
					}
				}
				list.add(value);
				value = null;
			} else if (mapContent.charAt(i) == LIST_END_CHAR) {
				if (value == null) {
					value = "";
				} else if (value instanceof String) {
					value = ((String) value).trim();
					if (nullStringAsNullObject && value.equals(nullString)) {
						value = null;
					} else if (convertPossibleNumeric) {
						try {
							value = Integer.parseInt((String) value);
						} catch (Exception e) {
						}
					}
				}
				list.add(value);
				return i;
			} else {
				if (mapContent.charAt(i) == MAP_START_CHAR) {
						value = new HashMap<String, Object>();
						int skipPos = convertStringToMap(mapContent.substring(i), (HashMap<String, Object>) value);
						i += skipPos;
				} else if (mapContent.charAt(i) == LIST_START_CHAR) {
					value = new ArrayList<Object>();
					int skipPos = convertStringToList(mapContent.substring(i), (List<Object>) value);
					i += skipPos;
				} else {
						if (value == null)
							value = "";
						value = (String)value + mapContent.charAt(i);
				}
			}
		}
		return 0;
	}
	
	public static Object convertStringToObject(String mapContent) {
		mapContent = mapContent.trim();
		Object value = null;
		if (mapContent.charAt(0) == MAP_START_CHAR) {
			value = new HashMap<String, Object>();
			convertStringToMap(mapContent.substring(0), (HashMap<String, Object>) value);
		} else if (mapContent.charAt(0) == LIST_START_CHAR) {
			value = new ArrayList<Object>();
			convertStringToList(mapContent.substring(0), (List<Object>) value);
		} else {
			// TODO create an exception for a not identified string argument cases
		}
		return value;
	}

}
